package apiserver

import (
	"context"
	"vite-tsc-gin/internal/apiserver/config"
	"vite-tsc-gin/internal/apiserver/store"
	"vite-tsc-gin/internal/apiserver/store/mysql"
	genericoptions "vite-tsc-gin/pkg/options"
	rediscluster "vite-tsc-gin/pkg/redis"
	genericapiserver "vite-tsc-gin/pkg/server"
)

/*
apiserver 包含
redis client
api  server
grpc 服务
*/
type apiServer struct {
	//gs               *shutdown.GracefulShutdown
	//gRPCAPIServer    *grpcAPIServer
	redisOptions     *genericoptions.RedisOptions
	genericAPIServer *genericapiserver.GenericAPIServer
	mysqlOptions     *genericoptions.MySQLOptions
}

type preparedAPIServer struct {
	*apiServer
}
type ExtraConfig struct {
	// Addr         string
	// MaxMsgSize   int
	// ServerCert   genericoptions.GeneratableKeyCert
	mysqlOptions *genericoptions.MySQLOptions
	// etcdOptions      *genericoptions.EtcdOptions
}

func createAPIServer(cfg *config.Config) (*apiServer, error) {
	// gs := shutdown.New()
	// gs.AddShutdownManager(posixsignal.NewPosixSignalManager())

	genericConfig, err := buildGenericConfig(cfg)
	if err != nil {
		return nil, err
	}

	genericServer, err := genericConfig.Complete().New()
	if err != nil {
		return nil, err
	}
	extraConfig, err := buildExtraConfig(cfg)
	if err != nil {
		return nil, err
	}
	err = extraConfig.complete().New()
	if err != nil {
		return nil, err
	}

	server := &apiServer{
		//gs:               gs,
		redisOptions:     cfg.RedisOptions,
		genericAPIServer: genericServer,
		//gRPCAPIServer:    extraServer,
	}

	return server, nil
}

func (s *apiServer) PrepareRun() preparedAPIServer {
	initRouter(s.genericAPIServer.Engine)

	s.initRedisStore()

	// s.gs.AddShutdownCallback(shutdown.ShutdownFunc(func(string) error {
	// 	mysqlStore, _ := mysql.GetMySQLFactoryOr(nil)
	// 	if mysqlStore != nil {
	// 		_ = mysqlStore.Close()
	// 	}

	// 	s.gRPCAPIServer.Close()
	// 	s.genericAPIServer.Close()

	// 	return nil
	// }))

	return preparedAPIServer{s}
}
func (s *apiServer) initRedisStore() {
	ctx, _ := context.WithCancel(context.Background())
	// s.gs.AddShutdownCallback(shutdown.ShutdownFunc(func(string) error {
	// 	cancel()

	// 	return nil
	// }))

	config := &rediscluster.Config{
		Host:                  s.redisOptions.Host,
		Port:                  s.redisOptions.Port,
		Addrs:                 s.redisOptions.Addrs,
		MasterName:            s.redisOptions.MasterName,
		Username:              s.redisOptions.Username,
		Password:              s.redisOptions.Password,
		Database:              s.redisOptions.Database,
		MaxIdle:               s.redisOptions.MaxIdle,
		MaxActive:             s.redisOptions.MaxActive,
		Timeout:               s.redisOptions.Timeout,
		EnableCluster:         s.redisOptions.EnableCluster,
		UseSSL:                s.redisOptions.UseSSL,
		SSLInsecureSkipVerify: s.redisOptions.SSLInsecureSkipVerify,
	}

	// try to connect to redis
	go rediscluster.ConnectToRedis(ctx, config)
}
func (s preparedAPIServer) Run() error {
	//go s.gRPCAPIServer.Run()

	// start shutdown managers
	// if err := s.gs.Start(); err != nil {
	// 	log.Fatalf("start shutdown manager failed: %s", err.Error())
	// }

	return s.genericAPIServer.Run()
}
func buildGenericConfig(cfg *config.Config) (genericConfig *genericapiserver.Config, lastErr error) {
	genericConfig = genericapiserver.NewConfig()
	if lastErr = cfg.GenericServerRunOptions.ApplyTo(genericConfig); lastErr != nil {
		return
	}

	if lastErr = cfg.SecureServing.ApplyTo(genericConfig); lastErr != nil {
		return
	}

	if lastErr = cfg.InsecureServing.ApplyTo(genericConfig); lastErr != nil {
		return
	}

	return
}

type completedExtraConfig struct {
	*ExtraConfig
}

// Complete fills in any fields not set that are required to have valid data and can be derived from other fields.
func (c *ExtraConfig) complete() *completedExtraConfig {
	return &completedExtraConfig{c}
}

// New create a grpcAPIServer instance.
func (c *completedExtraConfig) New() error {
	storeIns, err := mysql.GetMySQLFactoryOr(c.mysqlOptions)
	if err != nil {
		return err
	}
	store.SetClient(storeIns)
	return nil
}
func buildExtraConfig(cfg *config.Config) (*ExtraConfig, error) {
	return &ExtraConfig{
		mysqlOptions: cfg.MySQLOptions,
		// etcdOptions:      cfg.EtcdOptions,
	}, nil
}
